package net.kleinhenz.norabase.server;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import net.kleinhenz.norabase.client.LoginInfo;
import net.kleinhenz.norabase.client.LoginService;
import net.kleinhenz.norabase.server.model.Account;

import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Text;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class LoginServiceImpl extends RemoteServiceServlet implements LoginService {

	private static final long serialVersionUID = 1L;

	public LoginInfo login(String requestUri) {
		UserService userService = UserServiceFactory.getUserService();
		User user = userService.getCurrentUser();
		LoginInfo loginInfo = new LoginInfo();
		
		if (user != null) {
			EntityManager em = EMF.get().createEntityManager();
			loginInfo.setLoggedIn(true);
			loginInfo.setLogoutUrl(userService.createLogoutURL(requestUri));
			Account accountS = retrieveAccount(em, user.getEmail());
			if (accountS==null)
				accountS = createAccount(em, user.getEmail());
			em.close();
			net.kleinhenz.norabase.shared.model.Account accountC = new net.kleinhenz.norabase.shared.model.Account();
			copy(accountS, accountC);
			loginInfo.setAccount(accountC);
		} else {
			loginInfo.setLoggedIn(false);
			loginInfo.setLoginUrl(userService.createLoginURL(requestUri));
		}

		return loginInfo;
	}
	
	private Account createAccount(EntityManager em, String email) {
		Account account = new Account();
		account.setEmail(email);
		account.setUsername(email);
		em.persist(account);
		
		return account;
	}

	private void copy(Account from, net.kleinhenz.norabase.shared.model.Account to) {
		to.setId(KeyFactory.keyToString(from.getId()));
		to.setUsername(from.getUsername());
		to.setEmail(from.getEmail());
		if (from.getBattlegroupGridPreference()!=null)
			to.setBattlegroupGridPreference(from.getBattlegroupGridPreference().getValue());
		if (from.getSpellGridPreference()!=null)
		to.setSpellGridPreference(from.getSpellGridPreference().getValue());
		if (from.getChampionGridPreference()!=null)
		to.setChampionGridPreference(from.getChampionGridPreference().getValue());
		if (from.getEquipmentGridPreference()!=null)
		to.setEquipmentGridPreference(from.getEquipmentGridPreference().getValue());
		if (from.getRelicGridPreference()!=null)
		to.setRelicGridPreference(from.getRelicGridPreference().getValue());		
	}

	private void copy(net.kleinhenz.norabase.shared.model.Account from, Account to) {

		// id and email gets never changed yet
		//to.setId(KeyFactory.stringToKey(from.getId()));
		//to.setEmail(from.getEmail());
		to.setUsername(from.getUsername());
		to.setBattlegroupGridPreference(new Text(from.getBattlegroupGridPreference()));
		to.setSpellGridPreference(new Text(from.getSpellGridPreference()));
		to.setChampionGridPreference(new Text(from.getChampionGridPreference()));
		to.setEquipmentGridPreference(new Text(from.getEquipmentGridPreference()));
		to.setRelicGridPreference(new Text(from.getRelicGridPreference()));		
	}

	private Account retrieveAccount(EntityManager em, String email) {

		if (email==null || email.isEmpty())
			return null;

		Query q = em.createQuery("select from " + net.kleinhenz.norabase.server.model.Account.class.getName() + " where email=:email");
		q.setParameter("email", email);

		@SuppressWarnings("rawtypes")
		List l = q.getResultList();
		
		Account result = null;
		if (l.size()>1)
			throw new RuntimeException("Fatal: more than one account stored for id " + email);
		else if (!l.isEmpty())
			result = (Account)l.get(0);

		return result;
	}

	public static String getUser() {
		
		UserService userService = UserServiceFactory.getUserService();
		User user = userService.getCurrentUser();
		return user.getEmail();
	}

	@Override
	public void update(net.kleinhenz.norabase.shared.model.Account account) {

		EntityManager em = EMF.get().createEntityManager();

		if (account!=null) {
			Account accountS = retrieveAccount(em, account.getEmail());
			copy(account, accountS);
			em.merge(accountS);
		}
		em.close();
	}
}
